#include "ZModuleSettingsDOM.h"

ZModuleSettingsDOM::ZModuleSettingsDOM()
{
    loaded = false;
}

bool ZModuleSettingsDOM::load(const QString &configFileName)
{
    loaded = false;
    document = QDomDocument("module_configuration");
    QFile file(configFileName);
    if (!file.open(QIODevice::ReadOnly)) {
        lastError = "Failed to open file \""+configFileName+"\"";
        return false;
    }
    if (!document.setContent(&file)) {
        file.close();
        lastError = "Failed to associate dom document to file \""+configFileName+"\"";
        return false;
    }
    file.close();
    rootElement = document.documentElement();
    if(rootElement.nodeName() != "configuration") {
        document.clear();
        lastError = "Invalid tag \""+rootElement.nodeName()+"\"name for root node of the document";
        return false;
    }
    loaded = true;
    return true;
}

ZModuleSettings ZModuleSettingsDOM::get(const QString &moduleName)
{
    if(!isLoaded()) {
        lastError = "DOM document not loaded";
        return ZModuleSettings();
    }
    QString moduleId = moduleName.right(4);
    QString networkId = moduleName.left(2);
    QDomNode networkNode = rootElement.firstChild();
    while(!networkNode.isNull()) {
        QDomElement networkElement = networkNode.toElement();
        if(networkElement.attribute("id") == networkId) {
            QDomNode moduleNode = networkElement.firstChild();
            while(!moduleNode.isNull()) {
                QDomElement moduleElement = moduleNode.toElement();
                if(moduleElement.attribute("id") == moduleId) {
                    bool conversionOK = false;
                    int hbeatInterval = moduleElement.attribute("heartbeat", "-1").toInt(&conversionOK);
                    if(!conversionOK || hbeatInterval <= 0) {
                        lastError = "Invalid value \""+moduleElement.attribute("heartbeat", "-1")+"\" for heartbeat interval";
                        return ZModuleSettings(); //return invalid settings
                    }
                    int pingInterval = moduleElement.attribute("ping", "-1").toInt(&conversionOK);
                    if(!conversionOK || pingInterval <= 0) {
                        lastError = "Invalid value \""+moduleElement.attribute("ping", "-1")+"\" for ping interval";
                        return ZModuleSettings(); //return invalid settings
                    }
                    QString alias = moduleElement.attribute("alias", "");
                    ZModuleSettings settings(moduleName, hbeatInterval, pingInterval, alias);
                    QDomNode deviceNode = moduleElement.firstChild();
                    while(!deviceNode.isNull()) {
                        QDomElement deviceElement = deviceNode.toElement();
                        settings.getDevices().append(deviceElement.attribute("value", ""));
                        deviceNode = deviceNode.nextSibling();
                    }
                    return settings;
                }
                moduleNode = moduleNode.nextSibling();
            }
        }
        networkNode = networkNode.nextSibling();
    }
    lastError = "settings for module \""+moduleName+"\" not found in configuration file";
    return ZModuleSettings(); //return invalid settings
}

bool ZModuleSettingsDOM::remove(const QString& moduleName)
{
    if(!isLoaded()) {
        lastError = "DOM document not loaded";
        return false;
    }
    QString moduleId = moduleName.right(4);
    QString networkId = moduleName.left(2);
    QDomNode networkNode = rootElement.firstChild();
    while(!networkNode.isNull()) {
        QDomElement networkElement = networkNode.toElement();
        if(networkElement.attribute("id") == networkId) {
            QDomNode moduleNode = networkElement.firstChild();
            while(!moduleNode.isNull()) {
                QDomElement moduleElement = moduleNode.toElement();
                if(moduleElement.attribute("id") == moduleId) {
                    networkElement.removeChild(moduleNode);
                    return true;
                }
                moduleNode = moduleNode.nextSibling();
            }
        }
        networkNode = networkNode.nextSibling();
    }
    return true;
}

bool ZModuleSettingsDOM::set(const QString& moduleName, const ZModuleSettings& settings)
{
    if(!isLoaded()) {
        lastError = "DOM document not loaded";
        return false;
    }
    QString moduleId = moduleName.right(4);
    QString networkId = moduleName.left(2);
    QDomNode networkNode = rootElement.firstChild();
    while(!networkNode.isNull()) {
        QDomElement networkElement = networkNode.toElement();
        if(networkElement.attribute("id") == networkId) {
            QDomNode moduleNode = networkElement.firstChild();
            while(!moduleNode.isNull()) {
                QDomElement moduleElement = moduleNode.toElement();
                if(moduleElement.attribute("id") == moduleId) {
                    QDomElement newElement = createModuleNode(settings);
                    if(newElement.isNull())
                        return false;
                    networkElement.replaceChild(newElement, moduleNode);
                    return true;
                }
                moduleNode = moduleNode.nextSibling();
            }
            QDomElement newElement = createModuleNode(settings);
            if(newElement.isNull())
                return false;
            networkElement.appendChild(newElement);
            return true;
        }
        networkNode = networkNode.nextSibling();
    }
    networkNode = createNetworkNode(networkId);
    if(networkNode.isNull())
        return false;
    QDomElement moduleNode = createModuleNode(settings);
    if(moduleNode.isNull())
        return false;
    networkNode.appendChild(moduleNode);
    rootElement.appendChild(networkNode);
    return true;
}


bool ZModuleSettingsDOM::save(const QString& configFileName)
{
    if(!isLoaded()) {
        lastError = "DOM document not loaded";
        return false;
    }
    QString strDocument = document.toString();
    QFile file(configFileName);
    if(!file.open(QIODevice::WriteOnly)) {
        lastError = "Cannot open file \""+configFileName+"\"";
        file.close();
        return false;
    }
    QTextStream stream(&file);
    stream << strDocument;
    file.close();
    return true;
}

QDomElement ZModuleSettingsDOM::createNetworkNode(const QString &networkId)
{
    if(networkId.count() != 2) {
        lastError = "Invalid network id \""+networkId+"\"";
        return QDomElement();
    }
    QDomElement networkElement = document.createElement("network");
    networkElement.setAttribute("id", networkId);
    rootElement.appendChild(networkElement);
    return networkElement;
}

QDomElement ZModuleSettingsDOM::createModuleNode(const ZModuleSettings &settings)
{
    if(settings.getName().count() != 6) {
        lastError = "Invalid module name \""+settings.getName()+"\"";
        return QDomElement();
    }
    QDomElement moduleElement = document.createElement("module");
    moduleElement.setAttribute("id", settings.getName().right(4));
    moduleElement.setAttribute("heartbeat", settings.getHeartbeatInterval());
    moduleElement.setAttribute("ping", settings.getPingInterval());
    for(int i = 0; i < settings.getDevices().count(); i++) {
        QDomElement deviceElement = document.createElement("device");
        deviceElement.setAttribute("value", settings.getDevices().at(i));
        moduleElement.appendChild(deviceElement);
    }
    return moduleElement;
}

QString ZModuleSettingsDOM::generate()
{
    if(!loaded) return "";
    return document.toString();
}
